<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
    </style>
    <!--引入three.js三维引擎-->
    <script src="http://www.yanhuangxueyuan.com/3D/example/three.min.js"></script>
</head>

<body>
    <script>
        /**
         * 创建场景对象
         */
        var scene = new THREE.Scene();
        /**
         * 创建网格模型
         */
        var box = new THREE.BoxGeometry(50, 50, 50);//创建一个立方体几何对象
        var material = new THREE.MeshLambertMaterial({ color: 0x0000ff });//材质对象
        var mesh = new THREE.Mesh(box, material);//网格模型对象
        scene.add(mesh);//网格模型添加到场景中

        //球体网格模型
        var sphere = new THREE.SphereGeometry(20, 40, 40);//创建一个球体几何对象
        // var sphereMaterial = new THREE.MeshLambertMaterial({ color: 0xff0000 });//材质对象
        //设置透明度
        //更改场景中的球体材质对象构造函数THREE.MeshLambertMaterial()的参数，添加opacity和transparent属性，
        //opacity的值是0~1之间，transparent表示是否开启透明度效果， 默认是false表示透明度设置不起作用，值设置为true，网格模型就会呈现透明的效果，
        //使用下面的代码替换原来的球体网格模型的材质， 刷新浏览器可以看到半透明的球体和立方体颜色叠加融合的效果。
        // var sphereMaterial = new THREE.MeshLambertMaterial({
        //     color: 0xff0000,
        //     opacity: 0.7,
        //     transparent: true
        // });//材质对象
        //添加高光
        //
        //
        //
        var sphereMaterial = new THREE.MeshPhongMaterial({
            color: 0x0000ff,
            specular: 0x4488ee,
            shininess: 12
        });//材质对象
        var spereMesh = new THREE.Mesh(sphere, sphereMaterial);//网格模型对象
        scene.add(spereMesh);//网格模型添加到场景中
        spereMesh.translateY(70);//球体网格模型沿Y轴正方向平移100

        /**
         * 光源设置
         */
        //点光源
        var point = new THREE.PointLight(0xffffff);
        point.position.set(400, 200, 300);//点光源位置
        scene.add(point);//点光源添加到场景中
        //环境光
        var ambient = new THREE.AmbientLight(0x444444);
        scene.add(ambient);
        /**
         * 相机设置
         */
        var width = window.innerWidth;//窗口宽度
        var height = window.innerHeight;//窗口高度
        var k = width / height;//窗口宽高比
        var s = 100;//三维场景缩放系数
        //创建相机对象
        var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
        camera.position.set(200, 300, 200);//设置相机位置
        camera.lookAt(scene.position);//设置相机方向(指向的场景对象)
        /**
         * 创建渲染器对象
         */
        var renderer = new THREE.WebGLRenderer();
        renderer.setSize(width, height);
        renderer.setClearColor(0xb9d3ff, 1);//设置背景颜色
        document.body.appendChild(renderer.domElement);//body元素中插入canvas对象
        //执行渲染操作
        // renderer.render(scene, camera);

        //添加旋转动画
        // function render() {
        //     renderer.render(scene, camera);//执行渲染操作
        //     mesh.rotateY(0.01);//每次绕y轴旋转0.01弧度
        //     requestAnimationFrame(render);//请求再次执行渲染函数render
        // }
        // render();

        // 均匀旋转
        //   在实际执行程序的时候，可能requestAnimationFrame(render)请求的函数并不一定能按照理想的60FPS频率执行，
        //两次执行渲染函数的时间间隔也不一定相同， 如果执行旋转命令的rotateY的时间间隔不同，旋转运动就不均匀，
        //为了解决这个问题需要通过程序记录两次执行绘制函数的时间间隔。
        //   使用下面的渲染函数替换原来的渲染函数即可，rotateY()的参数是0.001*t，也意味着两次调用渲染函数执行渲染操作的间隔t毫秒时间内，
        //立方体旋转了0.001*t弧度，很显然立方体的角速度是0.001弧度每毫秒(0.0001 rad/ms = 1 rad/s = 180度/s)。
        //CPU和GPU执行一条指令时间是纳秒ns级，相比毫秒ms低了6个数量级，所以一般不用考虑渲染函数中几个计时语句占用的时间，
        //除非你编写的是要精确到纳秒ns的级别的标准时钟程序。
        let T0 = new Date();//上次时间
        function render() {
            let T1 = new Date();//本次时间
            let t = T1 - T0;//时间差
            T0 = T1;//把本次时间赋值给上次时间
            requestAnimationFrame(render);
            renderer.render(scene, camera);//执行渲染操作
            mesh.rotateY(0.001 * t);//旋转角速度0.001弧度每毫秒
        }
        render();


    </script>
</body>

</html>